#include <iostream>
#include <string.h>

using namespace std;

class String
{
public:
    String(const char *str = NULL);
    String(const String &obj);
    ~String();
    void show(void);
    String operator+(const String &op2);
    friend String operator+(const String &str1, const String &str2);

    // b = ++a
    String &operator++();
    // b = a++
    String operator++(int);

    String &operator=(const String &other);

    String &operator<<(const char *str);

    friend std::ostream &operator<<(std::ostream &os, const String &obj);

private:
    char *str;
};

std::ostream &operator<<(std::ostream &os, const String &obj)
{
    os << obj.str;
    return os;
}

String &String::operator<<(const char *str)
{
    int len = 0;
    char *old = NULL;
    if (!str)
    {
        return *this;
    }

    if (this->str)
    {
        len = strlen(this->str) + 1;
        old = this->str;
    }

    len += strlen(str);

    this->str = new char[len];

    if (old)
    {
        strcpy(this->str, old);
        delete[] old;
    }
    else
    {
        this->str[0] = '\0';
    }

    strcat(this->str, str);
    return *this;
}

String &String::operator=(const String &other)
{
    // a = a ==> a.operator=(a)
    if (this == &other)
    {
        return *this;
    }

    // a:"123"
    // b:"123456"
    // a = b
    if (this->str)
    {
        delete[] this->str;
    }

    if (other.str)
    {
        int len = strlen(other.str) + 1;
        this->str = new char[len];

        strcpy(this->str, other.str);
    }
    else
    {
        this->str = NULL;
    }
    return *this;
}

String &String::operator++()
{
    cout << "String &String::operator++()" << endl;
    for (char *p = str; p && *p; p++)
    {
        *p = *p + 1;
    }
    return *this;
}

String String::operator++(int)
{
    cout << "String String::operator++(int)" << endl;
    String old(*this);
    for (char *p = str; p && *p; p++)
    {
        *p = *p + 1;
    }
    return old;
}

String String::operator+(const String &op2)
{
    cout << "String::operator+(const String &op2)" << endl;
    String newStr;
    int len = strlen(this->str) + strlen(op2.str) + 1;

    newStr.str = new char[len];
    strcpy(newStr.str, this->str);
    strcat(newStr.str, op2.str);

    return newStr;
}

String::String(const char *str)
{
    cout << "String(const char *str)" << endl;
    if (str)
    {
        int len = strlen(str) + 1;
        this->str = new char[len];
        strcpy(this->str, str);
    }
    else
    {
        this->str = NULL;
    }
}

String::String(const String &obj)
{
    cout << "String(const String &obj)" << endl;
    if (obj.str)
    {
        int len = strlen(obj.str) + 1;
        this->str = new char[len];
        strcpy(this->str, obj.str);
    }
    else
    {
        this->str = NULL;
    }
}

String::~String()
{
    cout << "~String()" << endl;
    if (this->str)
    {
        int len = strlen(str) + 1;
        delete[] str;
    }
    str = NULL;
}

void String::show(void)
{
    for (char *p = str; p && (*p != '\0'); p++)
    {
        cout << *p << ", ascii: " << (int)*p << endl;
    }

    return;
}

String operator+(const String &str1, const String &str2)
{
    cout << "String operator+(const String &str1, const String &str2)" << endl;
    String newStr;
    int len = strlen(str1.str) + strlen(str2.str) + 1;

    newStr.str = new char[len];
    strcpy(newStr.str, str1.str);
    strcat(newStr.str, str2.str);

    return newStr;
}

int main()
{
    String str1("hello");
    String str2("world");

    // str1.str = str2.str
    str1 = str2;

    str1.show();
    cout << "---------------" << endl;
    str2.show();

    cout << "---------------" << endl;
    str2 << "12"
         << "34";
    str2.show();

    cout << str1 << endl;
    return 0;
}